import { debug } from 'debug'
import { LocalDate } from './Time';
import { readdirSync } from 'fs';
import { join, parse } from 'path';

let Debug = debug('server-libs');

/*提供一个加载流程，如果某一个步骤失败的话，会等待一定时间后重新调用，知道成功为止*/
export class InitMoudle {
    static initLoad: {
        func: (...args: any[]) => Promise<any>;
        caller: Object;
        args: any[];
    }[] = [];
    static regist(caller: any, func: (...args: any[]) => Promise<any>, ...args: any[]) {
        this.initLoad.push({
            func: func,
            args: args,
            caller: caller
        });
    }
    static initStep = 0;
    static initWait = 3000;
    static wait(num: number) {
        return new Promise<void>(function (resolve) {
            setTimeout(() => {
                resolve();
            }, num);
        });
    }
    static async startApp() {
        while (true) {
            try {
                await this.doWork();
                break;
            }
            catch (e) {
                let unit = this.initLoad[this.initStep];
                console.log(`init failed at step ${this.initStep} <${(unit.caller as Function).name}> wait ${this.initWait / 1000}s to reinit`);
                e && Debug('error', e);
            }
            finally {
                await this.wait(this.initWait);
            }
        }
        return true;
    }
    private static async doWork() {
        for (let i = 0; i < this.initLoad.length; i++) {
            let unit = this.initLoad[i];
            if (this.checkStep(i)) {
                await unit.func.apply(unit.caller, unit.args);
                console.log(`${(unit.caller as Function).name} init ok at Time`, LocalDate.formateString());
                this.setStep(i + 1);
            }
        }
        return true;
    }
    private static checkStep(num: number) {
        if (num == this.initStep)
            return true;
        return false;
    }
    private static setStep(num: number) {
        this.initStep = Math.max(this.initStep, num);
        return true;
    }
}

export function loadModule(dirName: string, initFn?: (modName: string, mod: any) => void) {
    let loadSet = new Set<string>()

    let files = readdirSync(dirName)
    for (let i = 0; i < files.length; i++) {
        let fpath = join(dirName, files[i])
        let pPath = parse(fpath);
        let modName = join(pPath.dir, pPath.name)
        // 给每个rpc初始化一下
        try {
            if (loadSet.has(modName)) continue;
            let rpcmod = require(modName)
            if (initFn) {
                initFn(modName, rpcmod)
            }
            loadSet.add(modName)
        }
        catch (e) {

        }
    }

    let result: string[] = []
    loadSet.forEach((v1, v2) => {
        result.push(v1.replace(dirName, ""))
    })

    return result
}